﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Media;
using SadlandVillage.Minigames.Mansion.Helper;
using SadlandVillage.Core.Helper;
using System.Timers;

namespace SadlandVillage.Minigames.Mansion
{
    public enum NanoGameState
    {
        CountDown,
        Running
    }

    public class Floor : Microsoft.Xna.Framework.DrawableGameComponent
    {
        //Events and Delegates
        public delegate void FloorLoserEventHandle(Room nextFloor);
        public event FloorLoserEventHandle FloorLoser;

        //Game dynamics attributes
        private NanoGameState gameState;
        private int lastTickCount = 0;
        private Color backColor = Color.Snow;

        //Drawing attributes
        private Texture2D matchArea;
        private Texture2D floorImage;
        private OutsideAreaPoint[,] floorData;
        private SpriteBatch sBatch;

        //Sounds attributes
        Song bgm1;
        SoundEffect scream;

        //Floor information attributes
        private Room nextFloor;
        private Room thisFloor;
        private Rectangle winArea;
        private Point startPoint;
        private int taskTime;

        //Countdown attributes
        private Timer timer;
        private int countDown = 0;

        //Points calculation attributes
        int dishContourPoints = 0;
        int dishMatchedPoints = 0;

        public Floor(Texture2D emptyTexture, Texture2D fullTexture, int timeToComplete,
            Rectangle winArea, Point startPoint, Room thisFloor,
            Room nextFloor, Song backGroundMusic1, SoundEffect scream, SpriteBatch sBatch)
            : base(GlobalContainer.game)
        {
            this.matchArea = emptyTexture;
            this.floorImage = fullTexture;
            this.nextFloor = nextFloor;
            this.taskTime = timeToComplete;
            this.winArea = winArea;
            this.startPoint = startPoint;
            this.thisFloor = thisFloor;
            this.sBatch = sBatch;
            this.bgm1 = backGroundMusic1;
            this.scream = scream;

            floorData = GetContour(matchArea, ref dishContourPoints);

            lastTickCount = 0;

            gameState = NanoGameState.CountDown;

            timer = new Timer(1000);
            timer.Elapsed += new ElapsedEventHandler(OnTimeElapsed);
        }

        protected void OnTimeElapsed(object sender, EventArgs e)
        {
            if (this.countDown > 0)
            {
                this.countDown--;
            }
            else
            {
                timer.Stop();
            }
        }

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            // TODO: Add your initialization code here

            base.Initialize();
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            if (MediaPlayer.State == MediaState.Stopped)
            {
                MediaPlayer.IsRepeating = true;
                MediaPlayer.Play(this.bgm1);
            }
            KeyboardState keyState = Keyboard.GetState();

            if (keyState.IsKeyDown(Keys.Escape))
            {
                FloorLoser(Room.None);
            }

            switch (gameState)
            {
                case NanoGameState.CountDown:
                    if (countDown == 0)
                    {
                        gameState = NanoGameState.Running;
                        lastTickCount = System.Environment.TickCount;
                        Mouse.SetPosition(750, 550);
                    }
                    break;
                case NanoGameState.Running:
                    MouseState state = Mouse.GetState();

                    if (IsInWinArea(state.Y, state.X))
                    {
                        FloorLoser(nextFloor);
                    }

                    if (IsInContour(state.Y, state.X))
                    {
                        this.scream.Play();
                        FloorLoser(Room.None);
                    }

                    if (CheckTime())
                    {
                        FloorLoser(Room.None);
                    }
                    break;
            }
            base.Update(gameTime);
        }

        protected void Dispose(bool disposing)
        {
            if (disposing)
            {
                timer.Dispose();
            }

            base.Dispose();
        }

        public override void Draw(GameTime gameTime)
        {
            SpriteFont font = (SpriteFont)GlobalContainer.services.GetService(typeof(SpriteFont));
            GraphicsDevice graphics = GlobalContainer.graphics;
            graphics.Clear(backColor);

            switch (gameState)
            {
                case NanoGameState.Running:
                    sBatch.Begin();

                    sBatch.DrawString(font, ((dishMatchedPoints * 100) / dishContourPoints).ToString() + "% completed", new Vector2(20, 20), Color.Black);

                    sBatch.DrawString(font, (((taskTime - (System.Environment.TickCount - lastTickCount)) / 1000) + 1).ToString() + " s", new Vector2(600, 20), Color.Black);
                    sBatch.End();

                    if (!Blink())
                    {
                        sBatch.Begin(SpriteBlendMode.AlphaBlend);

                        Color color = new Color(255, 255, 255, 255);
                        sBatch.Draw(floorImage, Vector2.Zero, Color.White);
                        sBatch.End();
                    }
                    break;
                case NanoGameState.CountDown:
                    sBatch.Begin();
                    sBatch.Draw(floorImage, Vector2.Zero, Color.Black);
                    StringEffects.PrintShadowedString(sBatch, StaticContainer.getReadyFont, "Get ready!", new Vector2(250, 150), Color.Yellow, Color.Black, 2);
                    StringEffects.PrintShadowedString(sBatch, StaticContainer.getReadyFont, countDown.ToString(), new Vector2(400, 285), Color.Yellow, Color.Black, 2);
                    sBatch.End();
                    break;
            }

            base.Draw(gameTime);
        }

        #region Helper
        private OutsideAreaPoint[,] GetContour(Texture2D countourTexture, ref int contours)
        {
            OutsideAreaPoint[,] result = new OutsideAreaPoint[countourTexture.Height, countourTexture.Width];
            uint[] array = new uint[countourTexture.Height * countourTexture.Width];
            countourTexture.GetData<uint>(array);

            for (int i = 0; i < countourTexture.Height; i++)
            {
                for (int j = 0; j < countourTexture.Width; j++)
                {
                    result[i, j] = new OutsideAreaPoint(array[i * countourTexture.Width + j] != 0);
                    if (result[i, j].IsContour)
                    {
                        contours++;
                    }
                }
            }

            return result;
        }

        private bool IsInContour(int x, int y)
        {
            bool result = false;

            int dim1 = floorData.GetLength(0);
            int dim2 = floorData.GetLength(1);

            if (x >= 0 && x < dim1 && y >= 0 && y < dim2)
            {
                if (floorData[x, y].IsContour)
                {
                    result = true;
                }
            }

            return result;
        }

        private bool IsInWinArea(int x, int y)
        {
            Console.WriteLine(x + " " + y + " " + GlobalContainer.graphics.Viewport.Width + " " + GlobalContainer.graphics.Viewport.Height + " " + winArea.X + " " + winArea.Y + " " + winArea.Width + " " + winArea.Height);
            Console.WriteLine((x >= 0 && x < GlobalContainer.graphics.Viewport.Width) + " " + (x >= 0 && x < GlobalContainer.graphics.Viewport.Width)
                + " " + (x >= winArea.X) + " " + (x <= (winArea.X + winArea.Width)) + " " + (y > winArea.Y) + " " + (y <= (winArea.Y + winArea.Height)));

            if (x >= 0 && x < GlobalContainer.graphics.Viewport.Width && x >= 0 && x < GlobalContainer.graphics.Viewport.Width)
            {
                if (x >= winArea.X && x <= (winArea.X + winArea.Width)
                    && y > winArea.Y && y <= (winArea.Y + winArea.Height))
                {
                    return true;
                }
            }

            return false;
        }

        private bool Blink()
        {
            System.Random r = new Random();
            bool result = false;
            if ((System.Environment.TickCount - lastTickCount) >= r.Next(3000,4500))
            {
                lastTickCount = System.Environment.TickCount;
                result = true;
            }
            return result;
        }

        private bool CheckTime()
        {
            bool result = false;
            if ((System.Environment.TickCount - lastTickCount) >= taskTime)
            {
                lastTickCount = System.Environment.TickCount;
                result = true;
            }
            return result;
        }
        #endregion
    }
}
